package com.huanyu.backend.study.concurrency.thread;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * 线程状态切换的例子
 * Java线程状态
 *
 * 初始状态(NEW)
 * 线程还没有调用start方法
 *
 * 运行状态(RUNNABLE)
 * 包含就绪和运行中两种状态
 * 就绪状态是指获取到除CPU资源外的其他资源
 * 运行中的状态是指获取到系统调度的CPU资源
 * yield会导致让出CPU执行权，处于就绪状态，有可能接着就获取到CPU资源从而进行运行中状态
 *
 * 阻塞状态(BLOCKED)
 * 等待进入synchronized方法或者块时会处于阻塞状态
 * 获取到锁进入运行状态
 *
 * 等待状态(WAITING)
 * 调用Object.wait方法，Thread.join方法，LockSupport.park方法会进入等待状态
 * 当调用Object.notify方法和notifyAll方法，以及LockSupport.unpark方法进入运行状态
 *
 * 超时等待状态(TIMED_WAITING)
 * 调用Thread.sleep(long)方法，Object.wait(long)方法，Thread.join(long)方法，
 * LockSupport.parkNanos()方法，LockSupport.parkUnit()方法会进入超时等待状态
 * 当调用Object.notify方法和notifyAll方法，LockSupport.unpark方法，以及超时时间到进入运行状态
 *
 * 终止 TERMINATED
 * 任务正常执行完成
 *
 * @author arron
 */
public class ThreadStatusSwitchExample {
    private static final Object object = new Object();
    private static final Object waitingObject = new Object();
    private static final Object timedWaitingObject = new Object();

    public static void main(String[] args) {
        Thread newT = new Thread();
        // NEW
        System.out.println("没有调用start方法时，线程当前状态: " + newT.getState());

        newT.start();
        // RUNNABLE
        System.out.println("调用start方法之后，线程当前状态: " + newT.getState());

        // BLOCKED
        produceBlockedThread();

        // WAITING
        produceWaitingThread();

        // TIMED_WAITING
        produceTimedWaitingThread();

        try {
            TimeUnit.MILLISECONDS.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // TERMINATED
        System.out.println("任务正常执行完成之后，线程当前状态: " + newT.getState());

        // IO阻塞时线程的状态为RUNNABLE
        produceIOBlockingThread();
    }

    private static void produceIOBlockingThread() {
        Thread ioBlockingThread = new Thread(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String url = "https://github.com/continuous1024/backend-study/file-list/master";
            OkHttpClient client = new OkHttpClient();

            Request request = new Request.Builder()
                    .url(url)
                    .build();

            try (Response response = client.newCall(request).execute()) {
                System.out.println("IO请求执行完成之后，请求的结果: " + response.message() + "，线程当前状态: " + Thread.currentThread().getState());
            } catch (IOException e) {
                e.printStackTrace();
            }

        });

        new Thread(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("调用IO请求之后，线程当前状态: " + ioBlockingThread.getState());
        }).start();

        ioBlockingThread.start();
    }

    private static void produceTimedWaitingThread() {
        Thread timedWaitingThread = new Thread(() -> {
            synchronized (timedWaitingObject) {
                try {
                    timedWaitingObject.wait(250);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("当超时时间到了之后，线程当前状态: " + Thread.currentThread().getState());
            }
        });

        new Thread(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("调用Object.wait(long)方法之后，线程当前状态: " + timedWaitingThread.getState());
        }).start();

        timedWaitingThread.start();
    }

    private static void produceWaitingThread() {
        Thread waitThread = new Thread(() -> {
            synchronized (waitingObject) {
                try {
                    waitingObject.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("当调用Object.notify方法被调用之后，线程当前状态: " + Thread.currentThread().getState());
            }
        });

        new Thread(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(150);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("调用Object.wait方法之后，线程当前状态: " + waitThread.getState());

            synchronized (waitingObject) {
                waitingObject.notify();
            }
        }).start();

        waitThread.start();
    }

    private static void produceBlockedThread() {
        Thread blockedThread = new Thread(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (object) {
                System.out.println("进入到synchronized块获取到锁之后，线程当前状态: " + Thread.currentThread().getState());
            }
        });

        new Thread(() -> {
            synchronized (object) {
                try {
                    TimeUnit.MILLISECONDS.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("等待进入synchronized块时，线程当前状态: " + blockedThread.getState());
            }
        }).start();

        blockedThread.start();
    }
}
